package com.mjk.common.core.jdbc.sphere.impl.table;


import com.mjk.common.core.jdbc.annotation.ArcSharding;
import com.mjk.common.core.jdbc.ctable.ShardingInfo;
import com.mjk.common.core.jdbc.sphere.StrategyEnum;
import com.mjk.common.util.TimeUtils;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;

import java.math.BigDecimal;
import java.util.*;


/**分表策略
 * @author zcy 2018年11月15日
 */
public class CapacityPreciseShardingAlgorithm implements ComplexKeysShardingAlgorithm {

  
    private final ArcSharding sharding;

    public CapacityPreciseShardingAlgorithm(ArcSharding sharding) {        
        this.sharding = sharding;
    }


    @Override
    public Collection<String> doSharding(Collection availableTargetNames,
			ComplexKeysShardingValue shardingValue) {
    	List<String> result = new ArrayList<>();
    	try {
        //String tableName = sharding.table();
        long manKey = -1;
        Collection<Object> index= (Collection<Object>) shardingValue.getColumnNameAndShardingValuesMap().get(sharding.key());
        Object subKey = null;
        Iterator<Object> iterator = index.iterator();
        if (iterator.hasNext()) {
        	String fristShardingValue = iterator.next().toString();
//            Object val = getShardingValue(fristShardingValue);
//            if (StrUtils.equals(fristShardingValue.getColumnName(), sharding.key())) {
                manKey = new BigDecimal(fristShardingValue).longValue();
//            } else if (StrUtils.equals(fristShardingValue.getColumnName(), sharding.subKey())) {
//                subKey = val;
//            }
        }

            ShardingInfo shardingInfo = sharding(this.sharding);
        	int length = shardingInfo.getShardingList().size();
//          if (subKey == null || length <= 1) {
            if(this.sharding.shardingNum()==0){
                result.add(this.sharding.table());
            }else {
                int shardingIndex = (int)manKey % length;
                result.add(buildFullTableName(this.sharding, shardingIndex));
            }
//        } else {
//            int keyHash = subKey.hashCode();
//            int shardingIndex = keyHash % length;
//            result.add(ShardingUtils.buildFullTableName(this.sharding, shardingIndex));
//        }
            return result;
    	}catch(Exception e) {
            result.add(buildFullTableName(this.sharding, 0));
    		return result;
    	}
    }
    
	public static  ShardingInfo sharding(ArcSharding sharding) {
		  List<String> result = new ArrayList<>();
		  ShardingInfo shardingInfo = new ShardingInfo(result);
		  if(sharding.strtegy().ordinal() == StrategyEnum.PRECISE.ordinal()) {
			  int maxCapacity = sharding.shardingNum();//
			  if (maxCapacity>0) {
			      if (maxCapacity == 1) {
			          shardingInfo.setUseSelfTable(true);
                      result.add(buildFullTableName(sharding));
			      } else {
			          for (int i = 0; i < maxCapacity ; i++) {
                          result.add(buildFullTableName(sharding, i));
			          }
			      }
			  } else {
			      shardingInfo.setUseCommonTable(true);
			      result.add(sharding.table());
			  }
		  }else if(sharding.strtegy().ordinal() == StrategyEnum.TIME.ordinal()) {
			 String time = TimeUtils.formatTime(new Date(),TimeUtils.DATE_FORMAT_DATEANDONEMON);
			  result.add(sharding.table().concat(sharding.concatChar()).concat(Objects.requireNonNull(time)));
		  }
		  return shardingInfo;
	}

    public static String buildFullTableName(ArcSharding sharding) {
        return sharding.table().concat(sharding.concatChar()).concat(sharding.key());
    }

    public static String buildFullTableName(ArcSharding sharding, Integer shardingIndex) {
        return sharding.table().concat(sharding.concatChar())
                .concat(String.valueOf(shardingIndex));
    }
}
